﻿using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Athena.RemoteAddress.Implementations
{
    using Serialization;
    public class PublicFileServiceAddressManager : BaseServiceAddressManager, IDisposable
    {
        private const string _fileExtendJson = ".athena";

        private string _publicSharedDirectoryPath;
        private readonly ServiceDescriptor _serviceDescriptor;
        private readonly ISerializer<string> _serializer;
        private readonly FileSystemWatcher _fileSystemWatcher;
        private readonly ILogger<PublicFileServiceAddressManager> _logger;

        private IEnumerable<ServiceAddressDescriptor> _serviceAddressDescriptors;

        public PublicFileServiceAddressManager(string publicSharedDirectoryPath, ServiceDescriptor serviceDescriptor, ISerializer<string> serializer, ILogger<PublicFileServiceAddressManager> logger)
        {
            _publicSharedDirectoryPath = publicSharedDirectoryPath;
            _serviceDescriptor = serviceDescriptor;
            _serializer = serializer;
            _logger = logger;
            _fileSystemWatcher = LoadFileSytemWatcher(_publicSharedDirectoryPath);
        }


        public override async Task<IEnumerable<ServiceAddressDescriptor>> GetServiceAddressAsync()
        {
            if (_serviceAddressDescriptors == null || _serviceAddressDescriptors.Count() == 0)
            {
                var files = Directory.GetFiles(_publicSharedDirectoryPath);
                var serviceDescriptors = new List<ServiceAddressDescriptor>();
                if (files.Length > 0)
                {
                    foreach (var item in files)
                    {
                        var serviceAddress = await BuildServiceAddressFromFile(item);
                        if (serviceAddress != null)
                        {
                            serviceDescriptors.Add(serviceAddress);
                        }
                    }
                }
                _serviceAddressDescriptors = serviceDescriptors;
            }
            return _serviceAddressDescriptors;
        }

        public override async Task SetServiceAddressAsync(IEnumerable<ServiceAddressDescriptor> serviceAddressDescriptors)
        {
            foreach (var serviceAddress in serviceAddressDescriptors)
            {
                var fileName = Path.Combine(_publicSharedDirectoryPath, serviceAddress.ServiceDescriptor.Name + _fileExtendJson);
                using (var fileStream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
                {
                    fileStream.SetLength(0);
                    using (var writer = new StreamWriter(fileStream, Encoding.UTF8))
                    {
                        await writer.WriteAsync(_serializer.Serialize(serviceAddress));
                    }
                }
            }
        }

        public void Dispose()
        {
            _fileSystemWatcher?.Dispose();
        }

        private FileSystemWatcher LoadFileSytemWatcher(string publicSharedFilePath)
        {
            //var directoryName = Path.GetDirectoryName(_publicSharedDirectoryPath);
            var fileSystemWatcher = new FileSystemWatcher(publicSharedFilePath);
            fileSystemWatcher.Created += FileSystemWatcherChanged;
            fileSystemWatcher.Changed += FileSystemWatcherChanged;
            fileSystemWatcher.Deleted += FileSystemWatcherChanged;
            fileSystemWatcher.Renamed += FileSystemWatcherChanged;
            fileSystemWatcher.IncludeSubdirectories = false;
            fileSystemWatcher.EnableRaisingEvents = true;
            return fileSystemWatcher;
        }

        private async void FileSystemWatcherChanged(object sender, FileSystemEventArgs e)
        {
            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation($"文件{_publicSharedDirectoryPath}发生了变更，重新获取地址信息。");
            }

            if (e.ChangeType == WatcherChangeTypes.Created || e.ChangeType == WatcherChangeTypes.Changed && !(AnalysisFileName(e.Name).Equals(_serviceDescriptor.Id)))
            {
                await EntryAddressModel(e.FullPath);
            }
        }

        private async Task<ServiceAddressDescriptor> BuildServiceAddressFromFile(string file)
        {
            string content = string.Empty;
            ServiceAddressDescriptor serviceAddressDescriptor = null;
            if (File.Exists(file))
            {
                if (_logger.IsEnabled(LogLevel.Debug))
                    _logger.LogDebug($"准备从文件：{file}中获取服务路由。");
                try
                {
                    using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    {
                        var reader = new StreamReader(fileStream, Encoding.UTF8);
                        content = await reader.ReadToEndAsync();
                    }
                }
                catch (IOException ioException)
                {
                    content = string.Empty;
                    if (_logger.IsEnabled(LogLevel.Error))
                    {
                        _logger.LogError(
                            $"成功获取路由信息失败：{ioException.Message}。");
                    }
                }
                try
                {
                    var serializer = _serializer;
                    serviceAddressDescriptor = (ServiceAddressDescriptor)serializer.Deserialize(content, typeof(ServiceAddressDescriptor));

                    if (_logger.IsEnabled(LogLevel.Information))
                        _logger.LogInformation(
                            $"成功获取到以下路由信息：{string.Join(",", serviceAddressDescriptor.AddressModelDescriptors.Select(x => x.CorrelationId))}。");
                }
                catch (Exception exception)
                {
                    if (_logger.IsEnabled(LogLevel.Error))
                        _logger.LogError("获取路由信息时发生了错误。", exception);
                }
            }
            else
            {
                if (_logger.IsEnabled(LogLevel.Warning))
                    _logger.LogWarning($"无法获取路由信息，因为文件：{file}不存在。");
            }
            return serviceAddressDescriptor;
        }

        private async Task EntryAddressModel(string file, bool isDelete = false)
        {
            if (isDelete)
            {

                var serviceId = AnalysisFileName(file);
                var serviceAddress = _serviceAddressDescriptors.FirstOrDefault(x => x.ServiceDescriptor.Id.Equals(serviceId));
                OnRemoved(new ServiceAddressEventArgs(serviceAddress));
            }
            else
            {
                var serviceAddress = (await BuildServiceAddressFromFile(file));
                if (serviceAddress != null && serviceAddress.ServiceDescriptor != null && serviceAddress.AddressModelDescriptors != null)
                {

                    var changeServiceAddress = _serviceAddressDescriptors.FirstOrDefault(x => x.ServiceDescriptor.Id.Equals(serviceAddress.ServiceDescriptor.Id));

                    if (changeServiceAddress == null)
                    {
                        _serviceAddressDescriptors.Concat(new ServiceAddressDescriptor[] { serviceAddress });
                        OnCreated(new ServiceAddressEventArgs(serviceAddress));
                    }
                    else
                    {
                        changeServiceAddress = serviceAddress;
                        OnChanged(new ServiceAddressEventArgs(serviceAddress));
                    }
                }
            }
        }

        private string AnalysisFileName(string fileName)
        {
            return fileName.Replace(_fileExtendJson, "");
        }

        public override Task ClearAsync()
        {
            _serviceAddressDescriptors = null;
            return Task.CompletedTask;
        }
    }
}
